package com.fs.iot.data;

import com.alibaba.fastjson.JSON;
import com.fs.common.utils.OgnlUtils;
import com.fs.iot.bean.dto.AlarmDTO;
import com.fs.iot.bean.dto.AlarmDefinePublishedDTO;
import com.fs.iot.service.AlarmDefinePublishedEntityService;
import com.fs.iot.service.AlarmEntityService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringSubstitutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 报警处理服务
 *
 * @author LiuQi 2025/3/24-19:19
 * @version V1.0
 **/
@Service
@Slf4j
public class AlarmCheckService {
    @Autowired
    private AlarmDefinePublishedEntityService publishedEntityService;

    @Autowired
    private AlarmEntityService alarmEntityService;

    @Autowired(required = false)
    private KafkaTemplate<String, String> kafkaTemplate;

    @Value("${iot.kafka.topic.alarm}")
    private String alarmTopic;

    /**
     * 实时工况
     */
    public void check(Map<String, Object> map) {
        String modelId = MapUtils.getString(map, "__modelId");
        List<AlarmDefinePublishedDTO> defineList = publishedEntityService.findByModel(modelId);
        if (CollectionUtils.isEmpty(defineList)) {
            return;
        }

        String deviceId = MapUtils.getString(map, "__deviceId");
        String deviceCode = MapUtils.getString(map, "__deviceCode");
        StringSubstitutor sb = new StringSubstitutor(map);
        String alarmTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        map.put("__alarmTime", alarmTime);

        List<AlarmDTO> alarms = new ArrayList<>(16);
        List<String> defineIds = new ArrayList<>(16);
        List<String> notAlarmDefineIds = new ArrayList<>(16);

        defineList.forEach(define -> {
            String rule = define.getRule();
            if (StringUtils.isBlank(rule)) {
                return;
            }

            Object result = OgnlUtils.execute(rule, map);

            if (null == result || result.equals(0) || "0".equals(result) || result == Boolean.FALSE || "false".equals(result)) {
                // 不需要报警
                if (define.getAutoClose()) {
                    notAlarmDefineIds.add(define.getId());
                }
                return;
            }

            // 其它情况，进行报警处理，但需要处理重复报警的情况
            AlarmDTO alarm = new AlarmDTO();
            alarms.add(alarm);
            alarm.setDeviceId(deviceId);
            alarm.setDeviceCode(deviceCode);
            alarm.setCategoryId(define.getCategoryId());
            alarm.setClosed(false);
            alarm.setDefineId(define.getId());
            alarm.setLevel(define.getLevel());
            alarm.setModelId(define.getModelId());
            alarm.setLastUpTime(LocalDateTime.now());
            alarm.setTenantId(define.getTenantId());

            // title与content需要处理参数
            alarm.setTitle(sb.replace(define.getTitle()));
            alarm.setContent(sb.replace(define.getContent()));
            defineIds.add(define.getId());
        });

        if (CollectionUtils.isEmpty(alarms)) {
            // 关闭需要自动关闭的报警
            alarmEntityService.closeAlarms(deviceId, notAlarmDefineIds);
            return;
        }

        // 报警不为空
        // 需要查询现有未完成的报警；相同报警定义的报警算同一条；
        List<AlarmDTO> dbAlarms = alarmEntityService.queryBuilder().eq("device_id", deviceId).in("define_id", defineIds).eq("closed", 0).query();
        Map<String, AlarmDTO> defineAlarmMap = dbAlarms.stream()
                .collect(Collectors.toMap(AlarmDTO::getDefineId, a -> a));
        alarms.forEach(alarm -> {
            String defineId = alarm.getDefineId();
            if (defineAlarmMap.containsKey(defineId)) {
                alarmEntityService.addAlarmCount(defineAlarmMap.get(defineId).getId());
            } else {
                alarm = alarmEntityService.insert(alarm);

                // 推送报警到kafka
                if (null != kafkaTemplate) {
                    kafkaTemplate.send(alarmTopic, JSON.toJSONString(alarm));
                }
            }
        });

        // 关闭需要自动关闭的报警
        alarmEntityService.closeAlarms(deviceId, notAlarmDefineIds);
    }
}
